﻿// lrpc.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>

#include "./include/rpc/lrpc/HLrpcApi.h"
#include "./include/rpc/lrpc/HLrpcHelper.h"
#include "./include/base/eec/autopinter.hpp"

#include <map>
#include <list>
#include <vector>

class LRPCMessageDeserializer : public rpc::lrpc::DESERIALIZE_MESSAGE_INFO {
public:
    typedef EEC_STD::function<void(unsigned char* _data, unsigned int _size)> HCompleteCallback;

public:
    LRPCMessageDeserializer(unsigned __int64 _index, const HCompleteCallback& _callback)
        : size_(0), index_(_index), callback_(_callback), offset_(0) {}

public:
    virtual unsigned __int64 index() { return index_; }

    virtual bool write(unsigned char* _in, unsigned int _size) {
        if (0 == _size || NULL == _in) {
            return true;
        }
        if (0 != size_ && (offset_ + _size) > size_) {
            return false;
        }

        data_.insert(data_.end(), _in, _in + _size);
        offset_ += _size;
        if (0 == size_ && data_.size() > 6) {
            if ('ES' != *(unsigned short*)(&data_[0])) {
                return false;
            }
            size_ = *(unsigned int*)(&data_[2]);
        }
        if (offset_ == size_) {
            callback_(&data_[6], size_ - 6);
            data_.resize(0);
            offset_ = 0;
            size_ = 0;
        }
        return true;
    }

private:
    unsigned __int64 index_;
    HCompleteCallback callback_;

    unsigned int size_;
    unsigned int offset_;
    std::vector<unsigned char> data_;
};

class LRPCMessageSerializer : public rpc::lrpc::SERIALIZE_MESSAGE_INFO {
public:
    LRPCMessageSerializer(unsigned __int64 _index, unsigned int _size, unsigned char* _data)
        : size_(6 + _size), offset_(0) {
        data_.resize(6);
        *(unsigned short*)(&data_[0]) = 'ES';
        *(unsigned int*)(&data_[2]) = size_;
        data_.insert(data_.end(), _data, _data + _size);
    }

public:
    virtual unsigned __int64 index() { return index_; }

    virtual void read(unsigned char* _out, unsigned int _max, unsigned int& _size, unsigned int _unique) {
        unsigned int l_offset = get_offset(_unique);
        _size = (size_ > (l_offset + _max)) ? _max : (size_ - l_offset);
        if (0 == _size) {
            return;
        }
        memcpy(_out, &data_[l_offset], _size);
        set_offset(l_offset + _size, _unique);
    }
    virtual unsigned int left(unsigned int _unique) { return size_ - get_offset(_unique); }
    virtual void offset(unsigned int _offset, unsigned int _unique) { set_offset(_offset, _unique); }
    virtual void end(unsigned int _status) {};

protected:
    inline unsigned int get_offset(unsigned int _unique) {
        if (0 == _unique) {
            return offset_;
        }
        base::eec::lock_guard<base::eec::mutex> l_guard(lock_);
        return threadid_2_offset_[_unique];
    }
    inline void set_offset(unsigned int _offest, unsigned int _unique) {
        if (0 == _unique) {
            offset_ = _offest;
        }
        base::eec::lock_guard<base::eec::mutex> l_guard(lock_);
        threadid_2_offset_[_unique] = _offest;
    }

private:
    unsigned __int64 index_;
    
    unsigned int size_;
    unsigned int offset_;
    std::vector<unsigned char> data_;

    base::eec::mutex lock_;
    std::map<unsigned int, unsigned int> threadid_2_offset_;
};

int main()
{
   
    int i = 0;
    rpc::lrpc::HLrpcService l_service;
    bool l_result = l_service.Initialize(L"\\RPC Control\\test_lrpc", [&l_service, &i](unsigned __int64 _index) {
        return base::eec::shared_ptr<rpc::lrpc::DESERIALIZE_MESSAGE_INFO>(new LRPCMessageDeserializer(_index, [&l_service,&i,_index](unsigned char* _data, unsigned int _size) {
            printf("timer %u, reciver data, index: %u, size: %u\r\n", (unsigned int)time(NULL), i, _size);
            if ((++i % 100000) == 0) {
            }
            l_service.SendToMessage(new LRPCMessageSerializer(0, _size, _data));
        })); 
    }, 1, 4);
    printf("initialize result: %u", (int)l_result);
    while (1) {
        Sleep(1000);
    }

    l_service.Uninitialize();



    std::cout << "Hello World!\n";
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件
